#pragma once
#ifndef OBR_PLANEMESH_H
#define OBR_PLANEMESH_H

#include "common.h"
#include "core/Mesh.h"

namespace OBR
{

class PlaneMesh : public Mesh, public Configurable<PlaneMesh>
{
public:
    float3 U, V, O, N;
    float area;

private:
    static std::shared_ptr<CudaProgram> program;
    static CudaBuffer sbt_data_payload;
    CudaBuffer d_sbt_idx_offsets;

public:
    PlaneMesh();
    ~PlaneMesh();

private:
    /* ---------------------------- override Mesh --------------------------- */

    /**
     * @brief get GAS build input
     *
     * @return OptixBuildInput
     */
    OptixBuildInput getASBuildInput() override;

    /**
     * @brief get GAS build options
     *
     * @return OptixAccelBuildOptions
     */
    OptixAccelBuildOptions getASBuildOptions() override;

public:
    void updateAABB() override;
    /* ----------------------- override VirtualProgramEntry ----------------------- */

    /**
     * @brief upload all instances to payload
     *
     */
    void uploadVirtualProgramPayload(
        std::vector<std::shared_ptr<VirtualProgramEntry>> instances) override;

    /**
     * @brief Get the device ptr for this type of payload (one for each most derived type)
     *
     * @return CUdeviceptr
     */
    CUdeviceptr getPayloadDevicePtr() override;

    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief Get the Program of this type
     *
     * @return std::shared_ptr<CudaProgram>
     */
    std::shared_ptr<CudaProgram> getProgram() override;

private:
    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief Get the Program Group Options of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupOptions &getProgramGroupOptions() override;

    /**
     * @brief Get the Program Group Desc of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupDesc &getProgramGroupDesc() override;

    /**
     * @brief Set the Program for this type
     *
     * @param prog std::shared_ptr<CudaProgram>
     */
    void setProgram(std::shared_ptr<CudaProgram> prog) override;

protected:
    /* ------------------------ override Configurable ----------------------- */

    /**
     * @brief initialize object from config
     *
     * @param config
     */
    void _buildFromConfig(const Json::Value &config) override;

    /**
     * @brief call add instance on build finish
     *
     */
    void _onBuildEnd() override;
};

} // namespace OBR

#endif